package com.chen.service.impl;

import cn.hutool.json.JSONUtil;
import com.chen.common.constant.MessageConstant;
import com.chen.common.result.PageResult;
import com.chen.common.utils.JwtUtil;
import com.chen.common.utils.ThreadLocalUtil;
import com.chen.judge.JudgeService;
import com.chen.judge.codesandbox.model.JudgeResult;
import com.chen.mapper.*;
import com.chen.popj.dto.ProblemDTO;
import com.chen.popj.dto.ProblemPageQueryDTO;
import com.chen.popj.dto.ProblemSubmitDTO;
import com.chen.popj.entity.*;
import com.chen.popj.vo.ContestVO;
import com.chen.popj.vo.ProblemListVO;
import com.chen.popj.vo.ProblemVO;
import com.chen.service.ElasticSearchService;
import com.chen.service.JudgeCaseService;
import com.chen.service.ProblemService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class ProblemServiceImpl implements ProblemService {

    @Autowired
    HttpServletRequest httpServletRequest;

    @Autowired
    ProblemMapper problemMapper;

    @Autowired
    ProblemSubmitMapper problemSubmitMapper;

    @Autowired
    SamplesMapper samplesMapper;

    @Autowired
    @Lazy
    JudgeService judgeService;

    @Autowired
    JudgeCaseService judgeCaseService;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    ContestCodeSubmitMapper contestCodeSubmitMapper;

    @Autowired
    ContestMapper contestMapper;

    @Autowired
    ElasticSearchService elasticSearchService;

    /**
     * 添加题目
     *
     * @param problemDTO
     */
    @Override
    @Transactional
    public void addProblem(ProblemDTO problemDTO) {
        // 输入输出样例
        List<Samples> samples = new ArrayList<>();
        List<Samples> sampleList = problemDTO.getSamples();
        sampleList.forEach(sample -> {
            Samples build = Samples.builder()
                    .input(sample.getInput())
                    .output(sample.getOutput())
                    .build();
            samples.add(build);
        });
//        System.out.println("输入输出样例");
//        System.out.println(samples);
        // 题目
        Problem problem = new Problem();
        BeanUtils.copyProperties(problemDTO, problem);

        // 插入题目
        String token = httpServletRequest.getHeader("Authorization");
        Map<String, Object> parseToken = JwtUtil.parseToken(token);
        problem.setUserId((Integer) parseToken.get("id"));
        problem.setJudgeCase(String.valueOf(JSONUtil.parse(sampleList)));
        problemMapper.addProblem(problem);

        samples.forEach(sample -> {
            sample.setProblemId(problem.getId());
        });
        // samples.forEach(System.out::println);
        // 添加题目关联的输入输入样例
        if (!samples.isEmpty()) {
            samplesMapper.addSample(samples);
        }

//        List<JudgeCase> judgeCases = problemDTO.getJudgeCases();

        ArrayList<JudgeCase> judgeCases = new ArrayList<>();
        List<JudgeCase> judgeCaseList = problemDTO.getJudgeCases();
        judgeCaseList.forEach((judgeCase -> {
            JudgeCase build = JudgeCase.builder()
                    .input(judgeCase.getInput())
                    .output(judgeCase.getOutput())
                    .build();
            judgeCases.add(build);
        }));

        System.out.println(judgeCases);
        judgeCases.forEach((judgeCase) -> {
            judgeCase.setProblemId(problem.getId());
        });
        // 添加题目相关的测试点
        if (!judgeCases.isEmpty()) {
            judgeCaseService.addJudgeCase(judgeCases);
        }
        //es添加题目
        problemDTO.setId(problem.getId());
        elasticSearchService.addProblem(problemDTO);

    }

    /**
     * 题目分页查询
     *
     * @param problemPageQueryDTO
     * @return
     */
    @Override
    public PageResult<ProblemListVO> pageQuery(ProblemPageQueryDTO problemPageQueryDTO) {
        Page<ProblemListVO> page = null;

        try {
            PageHelper.startPage(problemPageQueryDTO.getPage(), problemPageQueryDTO.getPageSize());
            page = problemMapper.pageQuery(problemPageQueryDTO);
        } catch (Exception e) {
            log.error(MessageConstant.PROBLEM_QUERY_FAILED);
            log.error("题目分页查询", e);
            throw new RuntimeException(MessageConstant.PROBLEM_QUERY_FAILED);
        }

        return new PageResult<>(page.getTotal(), page.getResult());
    }

    /**
     * 根据题目id查询题目详情
     *
     * @param problemId
     * @return
     */
    @Override
    public ProblemVO queryProblem(Integer problemId) {
        // 获取题目
        Problem problem = problemMapper.queryProblem(problemId);

        // 获取题目的输入输出样例
        List<Samples> samplesList = samplesMapper.queryById(problemId);

        // 封装ProblemVO
        ProblemVO problemVO = new ProblemVO();
        BeanUtils.copyProperties(problem, problemVO);
        problemVO.setSamplesList(samplesList);
        return problemVO;
    }

    /**
     * 添加用户提交的题目代码
     *
     * @param problemSubmitDTO
     */
    @Override
    @Transactional
    public Integer problemSubmit(ProblemSubmitDTO problemSubmitDTO, Integer contestId) {
        String token = httpServletRequest.getHeader("Authorization");
        Map<String, Object> parseToken = JwtUtil.parseToken(token);
        ProblemSubmit problemSubmit = new ProblemSubmit();
        BeanUtils.copyProperties(problemSubmitDTO, problemSubmit);
        problemSubmit.setUserId((Integer) parseToken.get("id"));
        // System.out.println(problemSubmitVO);
        // System.out.println(problemSubmit);
        problemMapper.problemSubmit(problemSubmit);
        Integer problemSubmitId = problemSubmit.getId();
//        CompletableFuture.runAsync((() -> judgeService.doJudge(problemSubmitId)));

        // 普通判题时该题提交次数加1
        if (contestId == null) {
            rabbitTemplate.convertAndSend("Judge.Direct", "Judge", problemSubmitId);
            Integer problemId = problemSubmitDTO.getProblemId();
            Problem problem = Problem.builder()
                    .id(problemId)
                    .submitNumber(1)
                    .build();
            problemMapper.updateById(problem);
        } else {
            // 比赛时创建一个比赛代码提交
            Problem problem = problemMapper.getById(problemSubmitDTO.getProblemId());
            ContestCodeSubmit contestCodeSubmit = ContestCodeSubmit.builder()
                    .contestId(contestId)
                    .title(problem.getTitle())
                    .submitTime(LocalDateTime.now())
                    .problemSubmitId(problemSubmitId)
                    .language(problemSubmitDTO.getLanguage())
                    .code(problemSubmitDTO.getCode())
                    .isFirstAc((short) 0)
                    .wrongCount(0)
                    .build();

            try {
                contestCodeSubmitMapper.save(contestCodeSubmit);
            } catch (Exception e) {
                log.error("添加用户代码时报错：", e);
            }

            ProblemSubmit problemSubmitBuild = ProblemSubmit.builder()
                    .id(problemSubmitId)
                    .contestCodeId(contestCodeSubmit.getId())
                    .build();
            problemSubmitMapper.updateById(problemSubmitBuild);

            // 比赛的题目提交次数加一
            ContestProblem contestProblem = ContestProblem.builder()
                    .problemId(problemSubmitDTO.getProblemId())
                    .contestId(contestId)
                    .submitNumber(1)
                    .build();
            contestMapper.updateByContestIdAndProblemId(contestProblem);

            //
            rabbitTemplate.convertAndSend("Contest.Direct", "Contest", problemSubmitId);
        }
        return problemSubmitId;
    }

    /**
     * 根据题目id获取题目信息
     *
     * @param problemId
     * @return
     */
    @Override
    public Problem getById(Integer problemId) {
        return problemMapper.getById(problemId);
    }

    /**
     * 根据提交id获取题目做题结果
     *
     * @param problemSubmitId
     * @return
     */
    @Override
    public JudgeResult getProblemResult(Integer problemSubmitId) {
        String judgeResultJSON = problemMapper.getProblemResult(problemSubmitId);
        System.out.println(judgeResultJSON);
        JudgeResult judgeResult = JSONUtil.toBean(judgeResultJSON, JudgeResult.class);
        return judgeResult;
    }

    /**
     * 根据比赛的题目ids和比赛id查询题目
     *
     * @param contestProblemIds
     * @param contestId
     * @return
     */
    @Override
    public List<ContestProblem> queryProblemByContestIds(List<Integer> contestProblemIds, Integer contestId) {
//        System.out.println(contestProblem);
        return problemMapper.queryProblemByContestIds(contestProblemIds, contestId);
    }

    /**
     * 根据题目id删除题目，同时也要删除用户的相关做题记录
     *
     * @param ids
     */
    @Override
    @Transactional
    public void delete(ArrayList<Integer> ids) {
        problemMapper.delete(ids);
        problemSubmitMapper.delete(ids);
    }
}
